package ofdinv

import (
	"encoding/xml"
	"sort"
	"strconv"
)

// CustomTagRoot 表示增值税发票的CustomTag.xml根结构，专用于增值税发票解析
type CustomTagRoot struct {
	XMLName                 xml.Name       `xml:"root"`                    // XML根元素，标识CustomTag.xml文档结构
	InvoiceNo               ObjectRefField `xml:"InvoiceNo"`               // 发票号码字段的ID引用
	IssueDate               ObjectRefField `xml:"IssueDate"`               // 开票日期字段的ID引用
	Buyer                   BuyerSection   `xml:"Buyer"`                   // 购买方信息段，包含购买方相关字段
	Seller                  SellerSection  `xml:"Seller"`                  // 销售方信息段，包含销售方相关字段
	TaxExclusiveTotalAmount ObjectRefField `xml:"TaxExclusiveTotalAmount"` // 合计金额（不含税）字段的ID引用
	TaxTotalAmount          ObjectRefField `xml:"TaxTotalAmount"`          // 合计税额字段的ID引用
	TaxInclusiveTotalAmount ObjectRefField `xml:"TaxInclusiveTotalAmount"` // 价税合计字段的ID引用
	InvoiceClerk            ObjectRefField `xml:"InvoiceClerk"`            // 开票人字段的ID引用
	GoodsInfos              []GoodsInfo    `xml:"GoodsInfos"`              // 商品信息集合，包含多个商品明细，增值税发票特有
	Note                    ObjectRefField `xml:"Note,omitempty"`          // 备注字段的ID引用，可选字段
	// 单页模式商品字段
	Item                 []ObjectRefField `xml:"Item,omitempty"`                 // 商品名称字段（单页模式）
	Specification        []ObjectRefField `xml:"Specification,omitempty"`        // 规格型号字段（单页模式）
	TaxScheme            []ObjectRefField `xml:"TaxScheme,omitempty"`            // 税率字段（单页模式）
	MeasurementDimension []ObjectRefField `xml:"MeasurementDimension,omitempty"` // 计量单位字段（单页模式）
	Amount               []ObjectRefField `xml:"Amount,omitempty"`               // 金额字段（单页模式）
	TaxAmount            []ObjectRefField `xml:"TaxAmount,omitempty"`            // 税额字段（单页模式）
	Price                []ObjectRefField `xml:"Price,omitempty"`                // 单价字段（单页模式）
	Quantity             []ObjectRefField `xml:"Quantity,omitempty"`             // 数量字段（单页模式）
}

// ObjectRefField 表示对象引用字段，包含多个页面对象引用
type ObjectRefField struct {
	ObjectRefs []ObjectRef `xml:"ObjectRef"` // 对象引用数组，每个元素指向页面中的一个文本对象
}

// ObjectRef 表示对象引用，定义页面中具体文本对象的引用信息
type ObjectRef struct {
	PageRef int    `xml:"PageRef,attr"` // 页面引用ID，标识文本对象所在的页面
	Text    string `xml:",chardata"`    // 对象ID文本内容，实际为页面中文本对象的ID值
}

// BuyerSection 表示购买方信息段，包含购买方相关字段的ID引用
type BuyerSection struct {
	BuyerName  ObjectRefField `xml:"BuyerName"`  // 购买方名称字段的ID引用
	BuyerTaxID ObjectRefField `xml:"BuyerTaxID"` // 购买方纳税人识别号字段的ID引用
}

// SellerSection 表示销售方信息段，包含销售方相关字段的ID引用
type SellerSection struct {
	SellerName  ObjectRefField `xml:"SellerName"`  // 销售方名称字段的ID引用
	SellerTaxID ObjectRefField `xml:"SellerTaxID"` // 销售方纳税人识别号字段的ID引用
}

// GoodsInfo 表示商品信息，定义单个商品明细项的ID引用（增值税发票专用）
type GoodsInfo struct {
	Item                 ObjectRefField `xml:"Item"`                 // 商品名称字段的ID引用
	Specification        ObjectRefField `xml:"Specification"`        // 规格型号字段的ID引用
	TaxScheme            ObjectRefField `xml:"TaxScheme"`            // 税率字段的ID引用
	MeasurementDimension ObjectRefField `xml:"MeasurementDimension"` // 计量单位字段的ID引用
	Amount               ObjectRefField `xml:"Amount"`               // 金额字段的ID引用
	TaxAmount            ObjectRefField `xml:"TaxAmount"`            // 税额字段的ID引用
	Price                ObjectRefField `xml:"Price"`                // 单价字段的ID引用
	Quantity             ObjectRefField `xml:"Quantity"`             // 数量字段的ID引用
}

// IDMapping 表示ID映射信息，定义页面对象ID与字段的对应关系
type IDMapping struct {
	PageRef   int      `json:"page_ref"`   // 页面引用ID，标识字段内容所在的页面
	ObjectIDs []string `json:"object_ids"` // 对象ID数组，包含字段对应的页面文本对象ID列表
}

// FieldMappings 表示增值税发票字段映射表，定义增值税发票字段的ID映射关系
type FieldMappings struct {
	InvoiceNo               IDMapping          `json:"invoice_no"`                 // 发票号码字段的ID映射
	IssueDate               IDMapping          `json:"issue_date"`                 // 开票日期字段的ID映射
	BuyerName               IDMapping          `json:"buyer_name"`                 // 购买方名称字段的ID映射
	BuyerTaxID              IDMapping          `json:"buyer_tax_id"`               // 购买方纳税人识别号字段的ID映射
	SellerName              IDMapping          `json:"seller_name"`                // 销售方名称字段的ID映射
	SellerTaxID             IDMapping          `json:"seller_tax_id"`              // 销售方纳税人识别号字段的ID映射
	TaxExclusiveTotalAmount IDMapping          `json:"tax_exclusive_total_amount"` // 合计金额（不含税）字段的ID映射
	TaxTotalAmount          IDMapping          `json:"tax_total_amount"`           // 合计税额字段的ID映射
	TaxInclusiveTotalAmount IDMapping          `json:"tax_inclusive_total_amount"` // 价税合计字段的ID映射
	InvoiceClerk            IDMapping          `json:"invoice_clerk"`              // 开票人字段的ID映射
	GoodsInfos              []GoodsInfoMapping `json:"goods_infos,omitempty"`      // 商品信息映射数组，包含多个商品明细的ID映射
	Note                    IDMapping          `json:"note,omitempty"`             // 备注字段的ID映射
}

// GoodsInfoMapping 表示商品信息映射，定义单个商品明细项的ID映射关系（增值税发票专用）
type GoodsInfoMapping struct {
	Item                 IDMapping `json:"item"`                  // 商品名称字段的ID映射
	Specification        IDMapping `json:"specification"`         // 规格型号字段的ID映射
	TaxScheme            IDMapping `json:"tax_scheme"`            // 税率字段的ID映射
	MeasurementDimension IDMapping `json:"measurement_dimension"` // 计量单位字段的ID映射
	Amount               IDMapping `json:"amount"`                // 金额字段的ID映射
	TaxAmount            IDMapping `json:"tax_amount"`            // 税额字段的ID映射
	Price                IDMapping `json:"price"`                 // 单价字段的ID映射
	Quantity             IDMapping `json:"quantity"`              // 数量字段的ID映射
}

func (c *CustomTagsRoot) GetFileLocs() []string {
	var fileLocs []string
	for _, tag := range c.CustomTag {
		fileLocs = append(fileLocs, tag.FileLoc)
	}
	return fileLocs
}

// GetPageFieldMappings 返回每页对应的字段映射表，支持混合模式（多页模式和单页模式）
func (c *CustomTagRoot) GetPageFieldMappings() []*FieldMappings {
	var pageMappings []*FieldMappings

	// 收集所有涉及的页面引用
	allPageRefs := c.getAllPageRefs()

	// 为每个页面构建字段映射表
	for _, pageRef := range allPageRefs {
		mappings := &FieldMappings{
			InvoiceNo:               c.getPageFieldMapping(c.InvoiceNo, pageRef),
			IssueDate:               c.getPageFieldMapping(c.IssueDate, pageRef),
			BuyerName:               c.getPageFieldMapping(c.Buyer.BuyerName, pageRef),
			BuyerTaxID:              c.getPageFieldMapping(c.Buyer.BuyerTaxID, pageRef),
			SellerName:              c.getPageFieldMapping(c.Seller.SellerName, pageRef),
			SellerTaxID:             c.getPageFieldMapping(c.Seller.SellerTaxID, pageRef),
			TaxExclusiveTotalAmount: c.getPageFieldMapping(c.TaxExclusiveTotalAmount, pageRef),
			TaxTotalAmount:          c.getPageFieldMapping(c.TaxTotalAmount, pageRef),
			TaxInclusiveTotalAmount: c.getPageFieldMapping(c.TaxInclusiveTotalAmount, pageRef),
			InvoiceClerk:            c.getPageFieldMapping(c.InvoiceClerk, pageRef),
			Note:                    c.getPageFieldMapping(c.Note, pageRef),
			GoodsInfos:              []GoodsInfoMapping{},
		}

		// 处理该页面的商品信息
		pageGoodsInfos := c.getGoodsInfosForPage(pageRef)
		for _, goodsInfo := range pageGoodsInfos {
			goodsMapping := GoodsInfoMapping{
				Item:                 extractIDMapping(goodsInfo.Item),
				Specification:        extractIDMapping(goodsInfo.Specification),
				TaxScheme:            extractIDMapping(goodsInfo.TaxScheme),
				MeasurementDimension: extractIDMapping(goodsInfo.MeasurementDimension),
				Amount:               extractIDMapping(goodsInfo.Amount),
				TaxAmount:            extractIDMapping(goodsInfo.TaxAmount),
				Price:                extractIDMapping(goodsInfo.Price),
				Quantity:             extractIDMapping(goodsInfo.Quantity),
			}
			mappings.GoodsInfos = append(mappings.GoodsInfos, goodsMapping)
		}

		// 只有当页面有实际内容时才添加到结果中
		if c.hasPageContent(mappings, pageGoodsInfos) {
			pageMappings = append(pageMappings, mappings)
		}
	}

	return pageMappings
}

// getAllPageRefs 获取所有涉及的页面引用
func (c *CustomTagRoot) getAllPageRefs() []int {
	pageRefs := make(map[int]bool)

	// 从基础字段收集页面引用
	fields := []ObjectRefField{
		c.InvoiceNo, c.IssueDate, c.Buyer.BuyerName, c.Buyer.BuyerTaxID,
		c.Seller.SellerName, c.Seller.SellerTaxID, c.TaxExclusiveTotalAmount,
		c.TaxTotalAmount, c.TaxInclusiveTotalAmount, c.InvoiceClerk, c.Note,
	}

	for _, field := range fields {
		for _, ref := range field.ObjectRefs {
			pageRefs[ref.PageRef] = true
		}
	}

	// 从多页模式商品收集页面引用
	for _, goodsInfo := range c.GoodsInfos {
		goodsFields := []ObjectRefField{
			goodsInfo.Item, goodsInfo.Specification, goodsInfo.TaxScheme,
			goodsInfo.MeasurementDimension, goodsInfo.Amount, goodsInfo.TaxAmount,
			goodsInfo.Price, goodsInfo.Quantity,
		}
		for _, field := range goodsFields {
			for _, ref := range field.ObjectRefs {
				pageRefs[ref.PageRef] = true
			}
		}
	}

	// 从单页模式字段收集页面引用
	singlePageFields := [][]ObjectRefField{
		c.Item, c.Specification, c.TaxScheme, c.MeasurementDimension,
		c.Amount, c.TaxAmount, c.Price, c.Quantity,
	}

	for _, fieldSlice := range singlePageFields {
		for _, field := range fieldSlice {
			for _, ref := range field.ObjectRefs {
				pageRefs[ref.PageRef] = true
			}
		}
	}

	// 转换为切片
	var result []int
	for pageRef := range pageRefs {
		result = append(result, pageRef)
	}

	return result
}

// getGoodsInfosForPage 获取指定页面的所有商品信息（多页模式和单页模式）
func (c *CustomTagRoot) getGoodsInfosForPage(pageRef int) []GoodsInfo {
	var goodsInfos []GoodsInfo

	// 处理多页模式的商品
	for _, goodsInfo := range c.GoodsInfos {
		// 检查商品是否属于当前页面（使用Item字段的页面引用）
		if len(goodsInfo.Item.ObjectRefs) > 0 && goodsInfo.Item.ObjectRefs[0].PageRef == pageRef {
			goodsInfos = append(goodsInfos, goodsInfo)
		}
	}

	// 处理单页模式的商品
	singlePageGoods := c.buildSinglePageGoodsInfo()
	if pageGoods, exists := singlePageGoods[pageRef]; exists {
		goodsInfos = append(goodsInfos, pageGoods...)
	}

	return goodsInfos
}

// buildSinglePageGoodsInfo 构建单页模式的商品信息 - 基于ObjectRef值范围的算法（适配原始结构体）
func (c *CustomTagRoot) buildSinglePageGoodsInfo() map[int][]GoodsInfo {
	pageGoodsMap := make(map[int][]GoodsInfo)

	// 定义边界项结构体
	type boundaryItem struct {
		refInt     int
		goodsIndex int
	}

	// 步骤1: 收集所有Item的ObjectRef值作为边界，同时记录对应的商品索引
	var itemBoundaries []boundaryItem
	for goodsIndex, itemField := range c.Item {
		for _, objRef := range itemField.ObjectRefs {
			refInt, err := strconv.Atoi(objRef.Text)
			if err == nil {
				itemBoundaries = append(itemBoundaries, boundaryItem{
					refInt:     refInt,
					goodsIndex: goodsIndex,
				})
			}
		}
	}

	// 如果没有Item，直接返回空结果
	if len(itemBoundaries) == 0 {
		return pageGoodsMap
	}

	// 对边界按refInt进行排序
	sort.Slice(itemBoundaries, func(i, j int) bool {
		return itemBoundaries[i].refInt < itemBoundaries[j].refInt
	})

	// 步骤2: 为每个Item创建空的GoodsInfo
	var goodsInfos []GoodsInfo
	for _, itemField := range c.Item {
		goodsInfo := GoodsInfo{
			Item: itemField, // 使用原始结构体字段名
		}
		goodsInfos = append(goodsInfos, goodsInfo)
	}

	// 步骤3: 辅助函数 - 根据ObjectRef值找到对应的商品索引
	findGoodsIndex := func(refInt int) int {
		for i := 0; i < len(itemBoundaries)-1; i++ {
			if refInt >= itemBoundaries[i].refInt && refInt < itemBoundaries[i+1].refInt {
				return itemBoundaries[i].goodsIndex
			}
		}
		// 如果在最后一个区间
		if refInt >= itemBoundaries[len(itemBoundaries)-1].refInt {
			return itemBoundaries[len(itemBoundaries)-1].goodsIndex
		}
		// 如果小于第一个边界，属于第一个商品
		if refInt < itemBoundaries[0].refInt {
			return itemBoundaries[0].goodsIndex
		}
		return -1 // 未找到
	}

	// 步骤4: 处理Specification字段
	for _, specField := range c.Specification {
		if len(specField.ObjectRefs) == 0 {
			continue
		}
		refInt, err := strconv.Atoi(specField.ObjectRefs[0].Text)
		if err == nil {
			goodsIndex := findGoodsIndex(refInt)
			if goodsIndex >= 0 && goodsIndex < len(goodsInfos) {
				goodsInfos[goodsIndex].Specification = specField
			}
		}
	}

	// 步骤5: 处理其他单值字段
	processSingleField := func(fields []ObjectRefField, setter func(*GoodsInfo, ObjectRefField)) {
		for _, field := range fields {
			if len(field.ObjectRefs) == 0 {
				continue
			}
			refInt, err := strconv.Atoi(field.ObjectRefs[0].Text)
			if err == nil {
				goodsIndex := findGoodsIndex(refInt)
				if goodsIndex >= 0 && goodsIndex < len(goodsInfos) {
					setter(&goodsInfos[goodsIndex], field)
				}
			}
		}
	}

	// 处理TaxScheme
	processSingleField(c.TaxScheme, func(goodsInfo *GoodsInfo, field ObjectRefField) {
		goodsInfo.TaxScheme = field
	})

	// 处理MeasurementDimension
	processSingleField(c.MeasurementDimension, func(goodsInfo *GoodsInfo, field ObjectRefField) {
		goodsInfo.MeasurementDimension = field
	})

	// 处理Amount
	processSingleField(c.Amount, func(goodsInfo *GoodsInfo, field ObjectRefField) {
		goodsInfo.Amount = field
	})

	// 处理TaxAmount
	processSingleField(c.TaxAmount, func(goodsInfo *GoodsInfo, field ObjectRefField) {
		goodsInfo.TaxAmount = field
	})

	// 处理Price
	processSingleField(c.Price, func(goodsInfo *GoodsInfo, field ObjectRefField) {
		goodsInfo.Price = field
	})

	// 处理Quantity
	processSingleField(c.Quantity, func(goodsInfo *GoodsInfo, field ObjectRefField) {
		goodsInfo.Quantity = field
	})

	// 步骤6: 按页面分组
	for _, goodsInfo := range goodsInfos {
		if len(goodsInfo.Item.ObjectRefs) > 0 {
			pageRef := goodsInfo.Item.ObjectRefs[0].PageRef
			pageGoodsMap[pageRef] = append(pageGoodsMap[pageRef], goodsInfo)
		}
	}

	return pageGoodsMap
}

// getPageFieldMapping 获取指定页面的字段映射
func (c *CustomTagRoot) getPageFieldMapping(field ObjectRefField, pageRef int) IDMapping {
	var objectIDs []string
	for _, ref := range field.ObjectRefs {
		if ref.PageRef == pageRef {
			objectIDs = append(objectIDs, ref.Text)
		}
	}
	if len(objectIDs) > 0 {
		return IDMapping{
			PageRef:   pageRef,
			ObjectIDs: objectIDs,
		}
	}
	return IDMapping{}
}

// hasPageContent 检查页面是否有实际内容
func (c *CustomTagRoot) hasPageContent(mappings *FieldMappings, goodsInfos []GoodsInfo) bool {
	// 检查基础字段是否有内容
	basicFields := []IDMapping{
		mappings.InvoiceNo, mappings.IssueDate, mappings.BuyerName,
		mappings.BuyerTaxID, mappings.SellerName, mappings.SellerTaxID,
		mappings.TaxExclusiveTotalAmount, mappings.TaxTotalAmount,
		mappings.TaxInclusiveTotalAmount, mappings.InvoiceClerk, mappings.Note,
	}

	for _, field := range basicFields {
		if len(field.ObjectIDs) > 0 {
			return true
		}
	}

	// 检查商品信息是否有内容
	if len(goodsInfos) > 0 {
		return true
	}

	return false
}

// extractIDMapping 从ObjectRefField提取ID映射
func extractIDMapping(field ObjectRefField) IDMapping {
	if len(field.ObjectRefs) == 0 {
		return IDMapping{}
	}

	// 假设所有ObjectRef都在同一个页面
	pageRef := field.ObjectRefs[0].PageRef
	objectIDs := make([]string, len(field.ObjectRefs))
	for i, ref := range field.ObjectRefs {
		objectIDs[i] = ref.Text
	}

	return IDMapping{
		PageRef:   pageRef,
		ObjectIDs: objectIDs,
	}
}
